﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Linq;

namespace Riba.MVVMSL
{
	///<summary>
	///<para>All ViewModels in your application should inherit from this base class to take advantage of the RIBA framework.</para>
	///</summary>
	public class ViewModelBase : INotifyPropertyChanged
	{
		///<summary>
		///<para>Is fired when ExchangeData and Callback (ChildWindow) have been correctly loaded and available.</para>
		///</summary>
		///<remarks>You need to register to this event and handle all data manipulation after the event is fired. Prior to this point ExchangeData is null.</remarks>
		public event EventHandler<ExchangeDataAvailableEventArgs> ExchangeDataAvailable;

		///<summary>
		///</summary>
		public class ExchangeDataAvailableEventArgs : EventArgs
		{
			///<summary>
			///</summary>
			///<param name="exchangeData"></param>
			///<param name="parentVM"></param>
			public ExchangeDataAvailableEventArgs(object exchangeData, ViewModelBase parentVM)
			{
				ExchangeData = exchangeData;
				ParentVM = parentVM;
			}

			///<summary>
			///<para>TODO</para>
			///</summary>
			///<value>null</value>
			public object ExchangeData { get; private set; }

			///<summary>
			///<para>View Model of the parent View</para>
			///</summary>
			///<value>null</value>
			public ViewModelBase ParentVM { get; private set; }
		}

		///<summary>
		/// Fired when a ChildWindow is closed
		///</summary>
		public event EventHandler<ChildWindowClosedEventArgs> ChildWindowClosed;

		///<summary>
		///</summary>
		public class ChildWindowClosedEventArgs : EventArgs
		{
			///<summary>
			///</summary>
			///<param name="dialogResult"></param>
			public ChildWindowClosedEventArgs(bool dialogResult)
			{
				DialogResult = dialogResult;
			}

			///<summary>
			///<para>TODO</para>
			///</summary>
			///<value>null</value>
			public bool DialogResult { get; private set; }
		}

		#region Properties

		///<summary>
		///<para>An object for private data manipulation ViewModel-child can be stored here if needed. This object is not shared across NavigatorControls-Views.</para>
		///</summary>
		///<value>null</value>
		public object PrivateData
		{
			get { return _privateData; }
			set
			{
				if (_privateData != value)
				{
					if (ExchangeDataDictionary.ContainsKey(GetType().Name))
						ExchangeDataDictionary[GetType().Name] = value;
				}

				SetPropertyValue(ref _privateData, value, () => PrivateData);
			}
		}
		private object _privateData;

		///<summary>
		///<para>ExchangeData can store data accessible across all ViewModels in the same NavigatorControl Hierarchy.</para>
		///</summary>
		///<value>null</value>
		public object ExchangeData
		{
			get { return _exchangeData; }
			set { SetPropertyValue(ref _exchangeData, value, () => ExchangeData); }
		}
		private object _exchangeData;

		///<summary>
		///<para>Delegate callback used in PassExchangeData.</para>
		///</summary>
		///<see cref="PassExchangeData"/>
		///<value>null</value>
		public Action<ViewModelBase, object> Callback
		{
			get { return _callback; }
			set { SetPropertyValue(ref _callback, value, () => Callback); }
		}
		private Action<ViewModelBase, object> _callback;

		///<summary>
		///<para>Must be set if the user should be informend about data changes before moving to another view.</para>
		///</summary>
		///<value>false</value>
		public bool IsDirty
		{
			get { return _isDirty; }
			set { SetPropertyValue(ref _isDirty, value, () => IsDirty); }
		}
		private bool _isDirty;

		///<summary>
		///<para>For use with BusyIndicator. Indicates that the Dialog's Domain Service is busy.</para>
		///</summary>
		///<value>false</value>
		public bool IsBusy
		{
			get { return _isBusy; }
			set { SetPropertyValue(ref _isBusy, value, () => IsBusy); }
		}
		private bool _isBusy;

		///<summary>
		///<para>Opposite of IsBusy.</para>
		///</summary>
		///<value>false</value>
		public bool IsNotBusy //TODO
		{
			get { return !IsBusy; }
		}

		///<summary>
		///<para>You can use the Notifier's event to notify other ViewModels registering for it.</para>
		///<para>Through a commonly known Tag the notified ViewModel can check if the notification was meant for it.</para>
		///<see cref="Notifier"/>
		///</summary>
		///<remarks>
		///<para>There might be situations where while ViewModel A is executing an asynchronous operation, the NavigatorControl is requested to bring in front ViewModel B, but the instantiation of ViewModel B depends on the ExchangeData of ViewModel A.</para>
		///<para>In these case <see cref="IsDirty"/> can be used as pollable property to some extent but there might be situations where an event broadcast is more elegant.</para>
		///<para>The purpose of the <see cref="Notifier"/>-Property is to be able to synchronize asynchronous operations across several ViewModels.</para>
		///</remarks>
		///<value>new Notifier()</value>
		public static Notifier Notifier { get; private set; }

		///<summary>
		///<para>A globally available dictionary that stores data accessible to all ViewModels.</para>
		///</summary>
		public static Dictionary<string, object> ExchangeDataDictionary { get; private set; }

		#endregion Properties

		///<summary>
		///<para>Initializes a new instance of the <see cref="ViewModelBase"/> class</para>
		///</summary>
		public ViewModelBase()
		{
			if (ExchangeDataDictionary == null)
				ExchangeDataDictionary = new Dictionary<string, object>();

			if (Notifier == null)
				Notifier = new Notifier();

			if (ExchangeDataDictionary.ContainsKey(GetType().Name))
				PrivateData = ExchangeDataDictionary[GetType().Name];
			else
			{
				PrivateData = null;
				ExchangeDataDictionary.Add(GetType().Name, PrivateData);
			}
		}

		#region INotifyPropertyChanged

		///<summary>
		///<para>Part of the automatic INotifyPropertyChanged implementation.</para>
		///<para>Derived ViewModels don't have to care about it.</para>
		///</summary>
		///<see cref="INotifyPropertyChanged"/>
		public event PropertyChangedEventHandler PropertyChanged;

		///<summary>
		///<para>Part of the automatic INotifyPropertyChanged implementation. Derived ViewModels don't have to care about it.</para>
		///<see cref="INotifyPropertyChanged"/>
		///</summary>
		///<param name="oldValue">oldValue</param>
		///<param name="newValue">newValue</param>
		///<param name="expression">expression</param>
		///<typeparam name="T">Type</typeparam>
		///<returns>True if value has been updated else false.</returns>
		public bool SetPropertyValue<T>
		(
			ref T oldValue,
			T newValue,
			Expression<Func<T>> expression)
		{
			if ((Equals(oldValue, default(T)) && Equals(newValue, default(T))) || Equals(oldValue, newValue))
				return false;

			oldValue = newValue;
			RaisePropertyChanged(expression);
			return true;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="propertyExpression"></param>
		public void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
		{
			var propertyName = ExtractPropertyName(propertyExpression);
			RaisePropertyChanged(propertyName);
		}

		private void RaisePropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
			{
				PropertyChanged
				(
					this,
					new PropertyChangedEventArgs(propertyName)
				);
			}
		}

		private static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
		{
			if (propertyExpression == null)
				throw new ArgumentNullException("propertyExpression");

			var memberExpression = propertyExpression.Body as MemberExpression;
			if (memberExpression == null)
				throw new ArgumentException("not a member expression", "propertyExpression");

			var property = memberExpression.Member as PropertyInfo;
			if (property == null)
				throw new ArgumentException("not a property", "propertyExpression");

			var getMethod = property.GetGetMethod(true);
			if (getMethod.IsStatic)
				throw new ArgumentException("can't be static", "propertyExpression");

			return memberExpression.Member.Name;
		}

		#endregion INotifyPropertyChanged


		#region IsInDesignTool

		///<summary>
		///<para>Gets a value indicating whether the control is in design mode (MS Blend or Visual Studio Designer) or not.</para>
		///</summary>
		///<remarks>Currently only working reliably in Silverlight. For WPF implementation see http://geekswithblogs.net/lbugnion/archive/2009/09/05/detecting-design-time-mode-in-wpf-and-silverlight.aspx .</remarks>
		///<value>false</value>
		public static bool IsInDesignTool
		{
			get { return DesignerProperties.IsInDesignTool; }
		}

		///<summary>
		///<para>Gets a value indicating whether the control is in design mode (MS Blend or Visual Studio Designer) or not.</para>
		///</summary>
		///<remarks>This is the instantiatable version of <see cref="IsInDesignTool"/>. Originally found in Laurent Bignon's GalaSoft.MVVMLight framework.</remarks>
		///<example>XAML: Visibility="{Binding IsInDesignMode, Converter={StaticResource BooleanToVisibilityConverter}}</example>
		///<value>false</value>
		[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Non static member needed for data binding in XAML")]
		public bool IsInDesignToolNonStatic
		{
			get { return IsInDesignTool; }
		}

		#endregion IsInDesignMode


		#region Load ChildWindow

		///<summary>
		///<para>Event containig informations needed to open a ChildWindow.</para>
		///</summary>
		///<see cref="ChildWindow"/>
		public event EventHandler<LoadChildWindowEventArgs> LoadChildWindow
		{
			add
			{
				//Prevent event from beeing added more then one time
				if (_loadChildWindow == null || !_loadChildWindow.GetInvocationList().Contains(value))
					_loadChildWindow += value;
			}
			remove
			{
				_loadChildWindow -= value;
				_loadChildWindow = null; //xxx.CloseChildWindowView -= null can be used to remove all event handlers
			}
		}

		private EventHandler<LoadChildWindowEventArgs> _loadChildWindow;

		///<summary>
		///<para>Notifies the View that a ChildWindow should be opened.</para>
		///</summary>
		public void RaiseLoadChildWindow(LoadChildWindowEventArgs e)
		{
			if (_loadChildWindow != null)
				_loadChildWindow(this, e);
		}

		///<summary>
		///<para>EventArgs used by LoadChildWindow.</para>
		///</summary>
		///<see cref="ViewModelBase.LoadChildWindow"/>
		public class LoadChildWindowEventArgs : EventArgs
		{
			///<summary>
			///<para>Must be a ChildWindow or a Control deriving from it.</para>
			///</summary>
			///<value>null</value>
			public Type ViewType { get; private set; }

			///<summary>
			///<para>Can be any data that must be passed to the ChildWindow.</para>
			///</summary>
			///<value>null</value>
			public object Data { get; private set; }

			///<summary>
			///<para>Callback called when the ChildWindow gets closed. The data (object) is passed to the respective ViewModel (ViewModelBase).</para>
			///</summary>
			///<value>null</value>
			public Action<ViewModelBase, object> Callback { get; private set; }

			///<summary>
			///<para>EventArgs used by <see cref="LoadChildWindow"/>.</para>
			///</summary>
			///<param name="viewType">Must be a ChildWindow or a Control inheriting from it</param>
			///<param name="data">Can be any data that must be passed to the <see cref="ChildWindow"/></param>
			///<param name="callback">Callback called when the <see cref="ChildWindow"/> gets closed. The data (object) is passed to the respective ViewModel (<see cref="ViewModelBase"/>)</param>
			public LoadChildWindowEventArgs(Type viewType, object data, Action<ViewModelBase, object> callback)
			{
				if (!viewType.IsSubclassOf(typeof(ChildWindow)))
					throw new ArgumentException("View not subclass of type ChildWindow");

				ViewType = viewType;
				Data = data;
				Callback = callback;
			}
		}

		///<summary>
		///Passes the ExchangeData during instantion of the deriving ViewModel.
		///</summary>
		///<param name="exchangeData">The <see cref="ExchangeData"/> object</param>
		///<param name="callback">A delegate of a method that must be notified when the operation is complete.</param>
		///<param name="parentVM"></param>
		public void PassExchangeData(object exchangeData, Action<ViewModelBase, object> callback, ViewModelBase parentVM)
		{
			ExchangeData = exchangeData;
			Callback = callback;

			if (ExchangeDataAvailable != null)
				ExchangeDataAvailable(this, new ExchangeDataAvailableEventArgs(exchangeData, parentVM));
		}

		///<summary>
		///</summary>
		public void SendChildWindowClosed(bool dialogResult)
		{
			if (ChildWindowClosed != null)
				ChildWindowClosed(this, new ChildWindowClosedEventArgs(dialogResult));
		}

		///<summary>
		///<para>Event raised by a ChildWindow- ViewModel to let its view close itself.</para>
		///</summary>
		///<see cref="ChildWindow"/>
		public event EventHandler CloseChildWindowView
		{
			add
			{
				//Prevent event from beeing added more then one time
				if (_closeChildWindowView == null || _closeChildWindowView.GetInvocationList().Contains(value))
					_closeChildWindowView += value;
			}
			remove
			{
				_closeChildWindowView -= value;
				_closeChildWindowView = null; //xxx.CloseChildWindowView -= null can be used to remove all event handlers
			}
		}

		private EventHandler _closeChildWindowView;

		///<summary>
		///<para>Notifies a ChildWindow View that a it should be closed.</para>
		///</summary>
		public void RaiseCloseChildWindowView()
		{
			if (_closeChildWindowView != null)
				_closeChildWindowView(this, null);
		}

		#endregion Load ChildWindow


		#region Navigator

		#region NavigateAutoSwap

		///<summary>
		///<para>Event containig informations needed to navigate automatically betwenn the current ContentControls of the NavigatorControl.</para>
		///</summary>
		public event EventHandler NavigateAutoSwap;

		///<summary>
		///<para>Starts the automatic navigation between the current ContentControls of NavigatorControl.</para>
		///</summary>
		public void RaiseNavigateAutoSwap()
		{
			if (NavigateAutoSwap != null)
				NavigateAutoSwap(this, null);
		}

		#endregion NavigateAutoSwap

		#region NavigateToView

		///<summary>
		///<para>Event containing informations needed to navigate with the NavigatorControl.</para>
		///</summary>
		public event EventHandler<NavigateToViewEventArgs> NavigateToView;

		///<summary>
		///<para>Contains informations of the currrently performed navigation.</para>
		///</summary>
		public class NavigateToViewEventArgs : EventArgs
		{
			///<summary>
			///<para>Any FrameWorkElement. This will be placed in the ContentControl2 of the NavigatorControl.</para>
			///</summary>
			///<value>null</value>
			public Type NavigateToViewType { get; private set; }

			///<summary>
			///<para>Defines an <see cref="AnimationMode"/>.</para>
			///</summary>
			///<value>AnimationMode.None</value>
			public AnimationMode Mode { get; private set; }

			///<summary>
			///<para>Navigates to the whished navigateToViewType using mode.</para>
			///</summary>
			///<param name="navigateToViewType">Any <see cref="FrameworkElement"/>. This will be placed in the ContentControl2 of the <see cref="NavigatorControl"/></param>
			///<param name="mode">Defines an <see cref="AnimationMode"/></param>
			public NavigateToViewEventArgs(Type navigateToViewType, AnimationMode mode)
			{
				NavigateToViewType = navigateToViewType;
				Mode = mode;
			}

			///<summary>
			///<para>Navigates to the whished navigateToViewType using the DefaultAnimationMode.</para>
			///</summary>
			///<param name="navigateToViewType">Any <see cref="FrameworkElement"/>. This will be placed in the ContentControl2 of the <see cref="NavigatorControl"/></param>
			public NavigateToViewEventArgs(Type navigateToViewType)
			{
				NavigateToViewType = navigateToViewType;
				Mode = new AnimationMode();
			}
		}

		///<summary>
		///<para>Starts the navigation with the whished NavigateToViewEventArgs</para>
		///</summary>
		///<param name="e">Aee <see cref="NavigateToViewEventArgs"/>.</param>
		public void RaiseNavigateToView(NavigateToViewEventArgs e)
		{
			if (NavigateToView != null)
				NavigateToView(this, e);
		}

		#endregion NavigateToView

		#region NavigationCompleted

		/// <summary>
		/// Navigation is completet
		/// </summary>
		public event EventHandler<EventArgs> NavigationCompleted;

		internal void NavigationComplete(object exchangeData, ViewModelBase parentVM)
		{
			ExchangeData = exchangeData;

			//WPF: parentVM is this if a VM is unloaded ! (Does not occur in Silverlight)

			// ExchangeDataAvailable will only be sent, if parentVM != this
			if (parentVM != this)
			{
				if (ExchangeDataAvailable != null)
					ExchangeDataAvailable(this, new ExchangeDataAvailableEventArgs(exchangeData, parentVM));
			}

			// NavigationCompleted will be sent in any case (for compatibility to WPF version)
			if (parentVM.NavigationCompleted != null)
				parentVM.NavigationCompleted(null, new EventArgs()); //Keine VM mehr geladen
		}

		#endregion NavigationCompleted

		#region NavigatorLoaded

		internal void NavigatorLoad()
		{
			if (NavigatorLoaded != null)
				NavigatorLoaded(this, new EventArgs());
		}

		///<summary>
		///<para>Is raised each time when the <see cref="NavigatorControl"/> is loaded.</para>
		///</summary>
		public event EventHandler NavigatorLoaded;

		#endregion NavigatorLoaded

		#endregion Navigator


		#region MessageBox

		///<summary>
		///<para>Is raised when a MessageBox must be shown.</para>
		///</summary>
		public event EventHandler<ShowMsgBoxEventArgs> ShowMsgBox
		{
			add
			{
				//Prevent event from beeing added more then one time
				if (_showMsgBox == null || !_showMsgBox.GetInvocationList().Contains(value))
					_showMsgBox += value;
			}
			remove
			{
				_showMsgBox -= value;
				//_showMsgBox = null; //remove all event handlers ?????????????????????????????????????????????????????????????
			}
		}

		private event EventHandler<ShowMsgBoxEventArgs> _showMsgBox;

		///<summary>
		///<para>Raises the <see cref="ShowMsgBox"/> event.</para>
		///</summary>
		///<param name="e">See <see cref="ShowMsgBoxEventArgs"/>.</param>
		public void RaiseShowMsgBox(ShowMsgBoxEventArgs e)
		{
			if (_showMsgBox != null)
				_showMsgBox(this, e);
		}

		///<summary>
		///<para>Contain all needed things to show up a System.MessageBox or a cusomized MessageBox.</para>
		///</summary>
		public class ShowMsgBoxEventArgs : EventArgs
		{
			///<summary>
			///<para>The message contained in the body.</para>
			///</summary>
			///<value>string.Empty</value>
			public string Content { get; private set; }

			///<summary>
			///<para>The title text.</para>
			///</summary>
			///<value>string.Empty</value>
			public string Caption { get; private set; }
			
			///<summary>
			///<para>The Buttons to display.</para>
			///</summary>
			///<remarks>Currently a fixed MessageBoxButton Enumeration. In future a flexible collection of customized Buttons could be implemented dipending on RIBA-users feedback.</remarks>
			///<see cref="MessageBoxButton"/>
			///<value>MessageBoxButton.OK</value>
			public MessageBoxButton Button { get; private set; }
			
			///<summary>
			///<para>The Callback that is executed when the MessageBox is closed or confirmed.</para>
			///</summary>
			///<value>null</value>
			public Action<MessageBoxResult> Callback { get; private set; }

			///<summary>
			///<para>Initializes a new instance of the <see cref="ShowMsgBoxEventArgs"/> class</para>
			///</summary>
			///<param name="content">See <see cref="Content"/>.</param>
			///<param name="caption">See <see cref="Caption"/>.</param>
			///<param name="button">See <see cref="Button"/>.</param>
			///<param name="callback">See <see cref="Callback"/>.</param>
			public ShowMsgBoxEventArgs(string content, string caption, MessageBoxButton button = MessageBoxButton.OK, Action<MessageBoxResult> callback = null)
			{
				Content = content;
				Caption = caption;
				Button = button;
				Callback = callback;
			}
		}

		#endregion MessageBox


		#region MessageWindow

		///<summary>
		///<para>Is raised when a MessageWindow must be shown.</para>
		///</summary>
		public event EventHandler<ShowMessageWindowEventArgs> ShowMessageWindow
		{
			add
			{
				//Prevent event from beeing added more then one time
				if (_showMessageWindow == null || !_showMessageWindow.GetInvocationList().Contains(value))
					_showMessageWindow += value;
			}
			remove
			{
				_showMessageWindow -= value;
				//_showMessageWindow = null; //remove all event handlers ?????????????????????????????????????????????????????????????
			}
		}

		private event EventHandler<ShowMessageWindowEventArgs> _showMessageWindow;

		///<summary>
		///<para>Raises the <see cref="ShowMessageWindow"/> event.</para>
		///</summary>
		///<param name="e">See <see cref="ShowMessageWindowEventArgs"/>.</param>
		public void RaiseShowMessageWindow(ShowMessageWindowEventArgs e)
		{
			if (_showMessageWindow != null)
				_showMessageWindow(this, e);
		}

		///<summary>
		///<para>Contain all needed things to show up a MessageWindow.</para>
		///</summary>
		public class ShowMessageWindowEventArgs : EventArgs
		{
			///<summary>
			///<para>The message contained in the body.</para>
			///</summary>
			///<value>string.Empty</value>
			public string Message { get; private set; }

			///<summary>
			///<para>The title text.</para>
			///</summary>
			///<value>string.Empty</value>
			public string Caption { get; private set; }

			///<summary>
			///</summary>
			public IList<MessageWindowButton> Buttons { get; private set; }

			///<summary>
			///<para>The Callback that is executed when the MessageWindow is closed with a button wit a Tag ???????????????????????.</para>
			///</summary>
			///<value>null</value>
			public Action<object > Callback { get; private set; }

			///<summary>
			///</summary>
			public Style MessageWindowStyle { get; private set; }

			///<summary>
			///<para>Initializes a new instance of the <see cref="ShowMessageWindowEventArgs"/> class</para>
			///</summary>
			///<param name="message">See <see cref="Message"/>.</param>
			///<param name="caption">See <see cref="Caption"/>.</param>
			///<param name="buttons">See <see cref="Buttons"/>.</param>
			///<param name="callback">See <see cref="Callback"/>.</param>
			///<param name="messageWindowStyle">See <see cref="MessageWindowStyle"/>.</param>
			public ShowMessageWindowEventArgs(string message, string caption, IList<MessageWindowButton> buttons = null, Action<object> callback = null, Style messageWindowStyle = null)
			{
				Message = message;
				Caption = caption;
				Buttons = buttons;
				Callback = callback;
				MessageWindowStyle = messageWindowStyle;
			}
		}

		#endregion MessageWindow


		#region OpenFileDialog

		///<summary>
		///<para>Is raised when a FileDialog must be shown.</para>
		///</summary>
		public event EventHandler<OpenFileDialogEventArgs> OpenFileDialog
		{
			add
			{
				//Prevent event from beeing added more then one time
				if (_openFileDialog == null || !_openFileDialog.GetInvocationList().Contains(value))
					_openFileDialog += value;
			}
			remove
			{
				_openFileDialog -= value;
				//_openFileDialog = null; //remove all event handlers ?????????????????????????????????????????????????????????????
			}
		}

		private event EventHandler<OpenFileDialogEventArgs> _openFileDialog;

		///<summary>
		///<para>Raises the <see cref="OpenFileDialog"/> event.</para>
		///</summary>
		///<param name="e">See <see cref="OpenFileDialogEventArgs"/>.</param>
		public void RaiseOpenFileDialog(OpenFileDialogEventArgs e)
		{
			if (_openFileDialog != null)
				_openFileDialog(this, e);
		}

		///<summary>
		///<para>Contain all needed things to show up a System.Windows.Controls.OpenFileDialog.</para>
		///</summary>
		public class OpenFileDialogEventArgs : EventArgs
		{
			///<summary>
			///<para>Gets or sets a filter string that specifies the file types and descriptions to display in the OpenFileDialog. See OpenFileDialog.Filter.</para>
			///</summary>
			///<value>string.Empty</value>
			public string Filter { get; private set; }

			///<summary>
			///<para>Gets or sets the index of the selected item in the OpenFileDialog filter drop-down list. See OpenFileDialog.FilterIndex.</para>
			///</summary>
			///<value>1</value>
			public int FilterIndex { get; private set; }

			///<summary>
			///<para>Gets or sets a value that indicates whether the OpenFileDialog allows users to select multiple files. See OpenFileDialog.Multiselect.</para>
			///</summary>
			///<value>false</value>
			public bool Multiselect { get; private set; }

			///<summary>
			///<para>The Callback that is executed when the User clicked OK in the File Dialog.</para>
			///</summary>
			///<value>null</value>
			public Action<IEnumerable<FileInfo>> Callback { get; private set; }

			///<summary>
			///<para>Initializes a new instance of the <see cref="OpenFileDialogEventArgs"/> class</para>
			///</summary>
			///<param name="filter">See <see cref="Filter"/>.</param>
			///<param name="filterIndex">See <see cref="FilterIndex"/>.</param>
			///<param name="multiselect">See <see cref="Multiselect"/>.</param>
			///<param name="callback">See <see cref="Callback"/>.</param>
			public OpenFileDialogEventArgs(string filter, int filterIndex, bool multiselect, Action<IEnumerable<FileInfo>> callback = null)
			{
				Filter = filter;
				FilterIndex = filterIndex;
				Multiselect = multiselect;
				Callback = callback;
			}
		}

		#endregion OpenFileDialog
	}
}
